import sys
import logging
import asyncio
import threading

from apscheduler.events import *
from apscheduler.triggers.date import DateTrigger
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
from apscheduler.executors.asyncio import AsyncIOExecutor
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.schedulers import SchedulerAlreadyRunningError, SchedulerNotRunningError

from .common import *

logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)


def up_scheduler():

	jobstores = {
		'default': SQLAlchemyJobStore(url=job_store_url)
	}

	executors = {
		'default': AsyncIOExecutor(),
		'threadpool': ThreadPoolExecutor(),
		'processpool': ProcessPoolExecutor(2)
	}

	job_defaults = {
		'coalesce': True,
		'max_instances': 3,
		'misfire_grace_time': 30
	}
	scheduler = AsyncIOScheduler(jobstores=jobstores, job_defaults=job_defaults, executors=executors, timezone='Asia/Shanghai')

	def scheduler_job_listener(event):
		if event.code == 2 ** 1:
			sys.stdout.writelines(f'监听器: 关闭调度器 \n')
		elif event.code == 2 ** 0:
			sys.stdout.writelines(f'监听器: 启动调度器 \n')
		elif event.code == 2 ** 12:
			sys.stdout.writelines(f'监听器: 作业 {event.job_id} 开始作业 \n')
		else:
			if event.exception:
				sys.stdout.writelines(f'作业: {event.job_id} 在 {event.scheduled_run_time} 执行失败 (: info: {event.exception.args[0]} \n')
			else:
				sys.stdout.writelines(f'作业: {event.job_id} 在 {event.scheduled_run_time} 执行成功 :) \n')
	scheduler.add_listener(scheduler_job_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR | EVENT_EXECUTOR_REMOVED | EVENT_SCHEDULER_SHUTDOWN | EVENT_SCHEDULER_STARTED)
	return scheduler


class SchedulerManage:

	def __init__(self, scheduler, jobstore='default'):
		self._scheduler = scheduler
		self.jobstore = jobstore

	def add_job(self, func, trigger, job_id, trigger_args, args=None, kwargs=None):
		"""
		:param func:
		:param str trigger: 触发器类型, cron, date, interval
		:param str job_id:
		:param dict | str trigger_args: 传指定时间
		:parm list args: 参数
		:parm dist kwargs: 参数
		:return: Job
		"""

		if trigger == 'cron':
			trigger = CronTrigger.from_crontab(trigger_args)
		elif trigger == "interval":
			trigger = IntervalTrigger(**trigger_args)
		elif trigger == 'date':
			trigger = DateTrigger(trigger_args)
		else:
			trigger = DateTrigger()

		return self._scheduler.add_job(func=func, trigger=trigger, id=job_id, args=args, kwargs=kwargs, replace_existing=True)

	def modify_job(self, job_id):
		return self._scheduler.modify_job(job_id=job_id)

	# 暂停job
	def pause_job(self, job_id):
		self._scheduler.pause_job(job_id)
		sys.stdout.writelines(f'作业: {job_id}, 已暂停作业 \n')

	# 恢复job
	def resume_job(self, job_id):
		self._scheduler.resume_job(job_id)
		sys.stdout.writelines(f'作业: {job_id}, 已恢复作业 \n')

	def get_job(self, job_id):
		return self._scheduler.get_job(job_id=job_id)

	def get_jobs(self):
		return self._scheduler.get_jobs()

	def remove_job(self, job_id=None):
		sys.stdout.writelines(f'作业: {job_id}, 已删除作业 \n')
		self._scheduler.remove_job(job_id=job_id)

	def remove_all_jobs(self):
		self._scheduler.remove_all_jobs()

	def print_jobs(self):
		return self._scheduler.print_jobs()

	def shutdown_scheduler(self):
		self._scheduler.shutdown()

	def start_scheduler(self):
		self._scheduler.start()

	# 获取当前调度器状态
	@property
	def state(self):
		return self._scheduler.state

	@property
	def run(self):
		return self._scheduler.timezone


scheduler = SchedulerManage(up_scheduler())


# 调度器线程
class SchedulerThread(threading.Thread):

	def __init__(self, scheduler, threadID):
		threading.Thread.__init__(self)
		self._scheduler = scheduler
		self._threadID = threadID
		self._msg = None
		self._flag = True

	def run(self) -> None:
		loop = None
		try:
			loop = asyncio.get_event_loop()
		except RuntimeError as ex:
			if "There is no current event loop in thread" in str(ex):
				loop = asyncio.new_event_loop()
				asyncio.set_event_loop(loop)
				loop = asyncio.get_event_loop()
		finally:
			scheduler.start_scheduler()
			loop.run_forever()
